home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Amiga Plus 2002 #3
/
Amiga Plus CD - 2002 - No. 03.iso
/
AmiSoft
/
Util
/
Arc
/
Checkx.lha
/
CheckX
/
sources
/
SortCheckX.c
< prev
next >
Wrap
C/C++ Source or Header
|
2002-12-30
|
21KB
|
613 lines
#define NAME "SortCheckX"
#define REVISION "3"
#define DISTRIBUTION "(Freeware) "
#define DATE "17.08.2002"
#define VERSION "1"
#define AUTHOR "by Dirk Stöcker <stoecker@epost.de>"
/* Programmheader
Name: SortCheckX
Author: SDI
Distribution: PD
Description: sorts CheckX output by file name to make comparisons possibly
Compileropts: -
Linkeropts: -gsi
1.0 14.08.02 : first version
1.1 15.08.02 : added OLDFIX, CRC and OUTFILE
1.2 16.08.02 : added buffered Output, optimized
1.3 17.08.02 : added secondary filesystem support
*/
#include <proto/dos.h>
#include <proto/exec.h>
#include <exec/memory.h>
#define version "$VER: " NAME " " VERSION "." REVISION " (" DATE ") " DISTRIBUTION AUTHOR
#define PARAM "INFILE/A,OUTFILE,OLDFIX/S,CRC/S"
struct Args {
STRPTR infile;
STRPTR outfile;
ULONG oldfix; /* tries to reduce the differences by fixing older texts */
ULONG crc;
};
struct CNode {
struct CNode *Prev;
struct CNode *Next;
struct CNode *Sub;
struct CNode *Head;
ULONG BufferPos; /* invalid after Sorting head structure */
ULONG Size;
UWORD Flags;
};
#define FLAG_DISKIMAGE (1<<0)
#define FLAG_INFOTEXT (1<<1)
#define FLAG_UNUSED (1<<2)
#define FLAG_CRC (1<<3)
#define FLAG_FILESYSTEM (1<<4)
#define OUTBUFSIZE 16384
struct MyOutBuf {
ULONG CurSize;
struct ExecBase *SysBase;
struct DosLibrary *DOSBase;
BPTR FileHandle;
UBYTE Buffer[OUTBUFSIZE];
};
struct MyReplace {
UWORD Offset;
UBYTE OldSize;
UBYTE NewSize;
};
/* This is a string field of replace strings:
First comes old, second the new string. Each ends with a '\n'.
The ReplaceField[] structure below contains offset and element sizes of this
string field.
Why? Because as result SortCheckX has no Relocs and is very short ;-)
*/
static const UBYTE StringField[] = {
"CheckX-Error 12: file is empty\n"
"CheckX-Warning 4: file is empty\n"
"CheckX-Error 4: read or write failed\n"
"CheckX-Error 4: reading failed\n"
"CheckX-Error 100: not enough memory\n"
"CheckX-Error 12: not enough memory for full tests\n"
"DMS-Archive\n"
"DMS (ARCHIVE)\n"
"LhA-Archive\n"
"LhA (ARCHIVE)\n"
"LhA-SFX-Archive\n"
"LhA SFX (ARCHIVE)\n"
"LhA-SFX (ARCHIVE)\n"
"LhA SFX (ARCHIVE)\n"
"LzX-Archive\n"
"LZX (ARCHIVE)\n"
"Zip-Archive\n"
"Zip (ARCHIVE)\n"
"ZOO-Archive\n"
"Zoo (ARCHIVE)\n"
"ZOO (ARCHIVE)\n"
"Zoo (ARCHIVE)\n"
};
#ifdef MAKEREPLACEFIELD /* in caseone is to lazy to count by hand ;-) */
void main(void)
{
LONG i = 0, n = 0, last = -1;
do
{
if(StringField[i] == '\n')
{
if(n++ & 1)
Printf(/*{*/" %2ld},\n", i-last);
else
Printf("{ %3ld, %2ld,"/*}*/, last+1, i-last);
last = i;
}
} while(StringField[++i]);
Printf("{ 0, 0, 0}\n");
}
#else
static const struct MyReplace ReplaceField[] = {
{ 0, 31, 32},
{ 63, 37, 31},
{ 131, 36, 50},
{ 217, 12, 14},
{ 243, 12, 14},
{ 269, 16, 18},
{ 303, 18, 18},
{ 339, 12, 14},
{ 365, 12, 14},
{ 391, 12, 14},
{ 417, 14, 14},
{ 0, 0, 0}
};
static LONG mystrncmp(STRPTR a, STRPTR b, ULONG s);
static void SortSubTree(struct CNode *curnode, STRPTR mem, struct ExecBase *SysBase);
static void MyOutput(STRPTR mem, ULONG size, struct MyOutBuf *outbuf);
ULONG start(void)
{
struct DosLibrary *DOSBase;
struct ExecBase *SysBase = (*((struct ExecBase **) 4));
{ /* test for WB and reply startup-message */
struct Process *task;
if(!(task = (struct Process *) FindTask(0))->pr_CLI)
{
WaitPort(&task->pr_MsgPort);
Forbid();
ReplyMsg(GetMsg(&task->pr_MsgPort));
return RETURN_FAIL;
}
}
if((DOSBase = (struct DosLibrary *) OpenLibrary("dos.library", 37)))
{
struct Args args;
struct RDArgs *rda;
args.oldfix = args.crc = 0;
args.outfile = 0;
if((rda = ReadArgs(PARAM, (LONG *) &args, 0)))
{
BPTR fh;
if(args.crc)
args.crc = FLAG_CRC;
if((fh = Open(args.infile, MODE_OLDFILE)))
{
struct FileInfoBlock *fib;
if((fib = (struct FileInfoBlock *) AllocDosObject(DOS_FIB, 0)))
{
if(ExamineFH(fh, fib))
{
STRPTR mem = version; /* removed by optimizer */
if((mem = (STRPTR) AllocMem(fib->fib_Size+1, 0)))
{
mem[fib->fib_Size] = '\n';
if(Read(fh, mem, fib->fib_Size) == fib->fib_Size)
{
/* This does no error checking and will produce total crap
with non-CheckX files, but should make no crash or other
dangerous error. */
ULONG i, depth1 = 0, depth2;
/* depth 1 --> number of '*', depth2 --> number of - types */
struct CNode *cbuf, *cbufp, *curnode;
/* depth2 is a short time used to count number of lines */
for(i = depth2 = 0; i < fib->fib_Size; ++i)
{
if(mem[i] == '\n' && mem[i+1] != ' ')
++depth2;
}
depth2 += 5; /* security */
if((cbuf = AllocVec(depth2*(sizeof(struct CNode))+sizeof(struct MyOutBuf), MEMF_CLEAR)))
{
struct MyOutBuf *outbuf = (struct MyOutBuf *) (cbuf+depth2);
outbuf->FileHandle = Output();
outbuf->DOSBase = DOSBase;
outbuf->SysBase = SysBase;
if(!args.outfile || (outbuf->FileHandle = Open(args.outfile, MODE_NEWFILE)))
{
depth2 = i = 0;
while(i < fib->fib_Size) /* skip the start texts */
{
if(!mystrncmp("Virus-Checking", mem+i, 14))
{
while(mem[i++] != '\n')
;
}
else if(!mystrncmp("The xvs.library", mem+i, 15))
{
while(mem[i++] != '\n')
;
}
else if(!mystrncmp("Your system memory", mem+i, 18))
{
while(mem[i++] != '\n')
;
}
else
break;
}
cbufp = cbuf;
/* the master header, no bytes */
curnode = cbufp++;
cbufp->Head = curnode;
curnode->Sub = cbufp;
/* the first line */
curnode = cbufp++;
curnode->BufferPos = i;
while(mem[i++] != '\n')
;
while(i < fib->fib_Size && mem[i] != '\n'
&& !(SetSignal(0L,0L) & SIGBREAKF_CTRL_C))
/* this is either the empty line or file end */
{
ULONG d, i2 = 0;
if(mem[i] != ' ') /* if ' ' attach a type line to current type */
{
if(args.crc)
{
for(i2 = 0; i2 < 9 && mem[i+i2] != '\n'; ++i2)
;
if(i2 != 9) i2 = 0;
}
if(!curnode->Size)
curnode->Size = i-curnode->BufferPos;
for(d = 0; mem[i+i2+d] == '*'; ++d)
;
if(d > depth1) /* a subtype */
{
cbufp->Head = curnode;
cbufp->BufferPos = i;
cbufp->Flags = args.crc;
curnode->Sub = cbufp;
curnode = cbufp++;
++depth1;
}
else if(d == depth1) /* equal or subtype 2 */
{
if(!mystrncmp("--infotext", mem+i+i2+d, 10))
{
if(curnode->Flags & (FLAG_INFOTEXT|FLAG_DISKIMAGE|FLAG_FILESYSTEM))
{
cbufp->Prev = curnode;
cbufp->Head = curnode->Head;
cbufp->BufferPos = i;
cbufp->Flags = FLAG_INFOTEXT|args.crc;
curnode->Next = cbufp;
curnode = cbufp++;
}
else
{
cbufp->Head = curnode;
cbufp->BufferPos = i;
cbufp->Flags = FLAG_INFOTEXT|args.crc;
if(curnode->Sub)
{
for(curnode = curnode->Sub; curnode->Next; curnode = curnode->Next)
;
curnode->Next = cbufp;
cbufp->Prev = curnode;
}
else
curnode->Sub = cbufp;
curnode = cbufp++;
++depth2;
}
}
else if(!mystrncmp("-disk image", mem+i+i2+d, 11))
{
if(curnode->Flags & (FLAG_INFOTEXT|FLAG_DISKIMAGE|FLAG_FILESYSTEM))
{
cbufp->Prev = curnode;
cbufp->Head = curnode->Head;
cbufp->BufferPos = i;
cbufp->Flags = FLAG_DISKIMAGE|args.crc;
curnode->Next = cbufp;
curnode = cbufp++;
}
else
{
cbufp->Head = curnode;
cbufp->BufferPos = i;
cbufp->Flags = FLAG_DISKIMAGE|args.crc;
if(curnode->Sub)
{
for(curnode = curnode->Sub; curnode->Next; curnode = curnode->Next)
;
curnode->Next = cbufp;
cbufp->Prev = curnode;
}
else
curnode->Sub = cbufp;
curnode = cbufp++;
++depth2;
}
}
else /* new equal type */
{
if(curnode->Flags & (FLAG_INFOTEXT|FLAG_DISKIMAGE|FLAG_FILESYSTEM))
{
--depth2;
curnode = curnode->Head;
SortSubTree(curnode, mem, SysBase);
}
cbufp->Prev = curnode;
cbufp->Head = curnode->Head;
cbufp->BufferPos = i;
cbufp->Flags = args.crc;
curnode->Next = cbufp;
curnode = cbufp++;
}
}
else /* leave that level depth1-d times, take care for depth2 and sizes */
{
/* set sizes! */
while(depth1 > d || curnode->Flags & (FLAG_INFOTEXT|FLAG_DISKIMAGE|FLAG_FILESYSTEM))
{
if(curnode->Flags & (FLAG_INFOTEXT|FLAG_DISKIMAGE|FLAG_FILESYSTEM))
--depth2;
else
--depth1;
curnode = curnode->Head;
SortSubTree(curnode, mem, SysBase);
}
continue; /* parse this again */
}
}
else
{
for(d = 0; mem[i+d] == ' '; ++d)
;
if(args.crc) d -= 9;
if(d <= depth1 || curnode->Flags & (FLAG_INFOTEXT|FLAG_DISKIMAGE|FLAG_FILESYSTEM))
{
if(!curnode->Size)
curnode->Size = i-curnode->BufferPos;
while(depth1 >= d)
{
if(curnode->Flags & (FLAG_INFOTEXT|FLAG_DISKIMAGE|FLAG_FILESYSTEM))
--depth2;
else
--depth1;
curnode = curnode->Head;
SortSubTree(curnode, mem, SysBase);
}
cbufp->Prev = curnode;
cbufp->Head = curnode->Head;
cbufp->BufferPos = i;
cbufp->Flags = FLAG_FILESYSTEM|args.crc;
curnode->Next = cbufp;
curnode = cbufp++;
}
}
while(mem[i++] != '\n')
;
}
if(i > fib->fib_Size)
i = fib->fib_Size;
if(!curnode->Size)
curnode->Size = i-curnode->BufferPos;
while(curnode->Head)
{
curnode = curnode->Head;
SortSubTree(curnode, mem, SysBase);
}
/* curnode now represents a complete tree, where each entry starts
with a filename (or disk image, infotext) and may have additional
texts after the first line. For a file information tree only use
first line (except for filesystem which has no name)!
*/
if(curnode->BufferPos && !(SetSignal(0L,0L) & SIGBREAKF_CTRL_C))
MyOutput(mem, curnode->BufferPos, outbuf);
cbufp = cbuf->Sub;
while(cbufp && !(SetSignal(0L,0L) & SIGBREAKF_CTRL_C))
{
if(args.oldfix)
{
STRPTR buf, bufend, beg;
buf = mem+cbufp->BufferPos;
bufend = buf+cbufp->Size;
while(buf < bufend)
{
beg = buf;
if(*buf == ' ')
{
const struct MyReplace *mr = ReplaceField;
while(*buf == ' ')
++buf;
MyOutput(beg, buf-beg, outbuf);
beg = buf;
while(mr->OldSize && mystrncmp(buf,
((STRPTR)StringField)+mr->Offset, mr->OldSize))
++mr;
if(mr->OldSize)
{
MyOutput(((STRPTR)StringField)+mr->OldSize+mr->Offset,
mr->NewSize, outbuf);
buf += mr->OldSize;
continue;
}
}
while(buf < bufend && *(buf++) != '\n')
;
MyOutput(beg, buf-beg, outbuf);
}
}
else
MyOutput(mem+cbufp->BufferPos, cbufp->Size, outbuf);
if(cbufp->Sub) cbufp = cbufp->Sub;
else if(cbufp->Next) cbufp = cbufp->Next;
else
{
cbufp = cbufp->Head;
while(cbufp && !cbufp->Next)
cbufp = cbufp->Head;
if(cbufp) cbufp = cbufp->Next;
}
}
if(i < fib->fib_Size && !(SetSignal(0L,0L) & SIGBREAKF_CTRL_C))
MyOutput(mem+i, fib->fib_Size-i, outbuf);
if(outbuf->CurSize)
Write(outbuf->FileHandle, outbuf->Buffer, outbuf->CurSize); /* Flush buffer */
if(args.outfile)
Close(outbuf->FileHandle);
}
FreeVec(cbuf);
}
}
FreeMem(mem, fib->fib_Size+1);
}
}
FreeDosObject(DOS_FIB, fib);
}
if(fh)
Close(fh);
}
FreeArgs(rda);
}
CloseLibrary((struct Library *) DOSBase);
}
return 0;
}
#define DOSBase outbuf->DOSBase
#define SysBase outbuf->SysBase
static void MyOutput(STRPTR mem, ULONG size, struct MyOutBuf *outbuf)
{
ULONG maxs;
do
{
maxs = OUTBUFSIZE - outbuf->CurSize;
if(maxs > size)
maxs = size;
CopyMem(mem, outbuf->Buffer+outbuf->CurSize, maxs);
outbuf->CurSize += maxs;
mem += maxs;
size -= maxs;
if(outbuf->CurSize == OUTBUFSIZE)
{
Write(outbuf->FileHandle, outbuf->Buffer, OUTBUFSIZE);
outbuf->CurSize = 0;
}
} while(size);
}
#undef SysBase
#undef DOSBase
static LONG mystrncmp(STRPTR a, STRPTR b, ULONG s)
{
while(s && *a && *a == *b)
{
++a; ++b; --s;
}
return s ? (*a - *b) : 0;
}
#define mytolower(a) ((a >= 'A' && a <= 'Z') || (a >= 0xC0 && a <= 0xDE) ? a+32 : a)
/* Sorts case insensitive, when equal the case is used for sorting,
if still equal the order is undefined! */
static LONG MyNodeComp(struct CNode *list, struct CNode *new, STRPTR mem)
{
STRPTR l, n;
LONG d, e;
if(list->Flags & (FLAG_UNUSED|FLAG_DISKIMAGE|FLAG_INFOTEXT|FLAG_FILESYSTEM)) /* always greater */
return 1000;
l = mem+list->BufferPos;
n = mem+new->BufferPos;
if(new->Flags & FLAG_CRC)
{
for(d = 0; d < 9 && l[d] != '\n' && n[d] != '\n'; ++d)
;
if(d == 9)
{
l += d;
n += d;
}
}
d = 0;
while(!(e = (mytolower(*l) - mytolower(*n))) && *l != '\n')
{
if(*l != *n && !d) /* sort by case if equal */
d = *l-*n;
++l; ++n;
}
return (e ? e : d);
}
static struct CNode *InsertFront(struct CNode *list, struct CNode *newnode)
{
struct CNode *next;
if((next = newnode->Next))
next->Prev = 0;
newnode->Next = list;
if((newnode->Prev = list->Prev))
newnode->Prev->Next = newnode;
list->Prev = newnode;
return next;
}
static void SortSubTree(struct CNode *curnode, STRPTR mem, struct ExecBase *SysBase)
{
struct CNode *oldlist, *list, dummylast;
/* list = list of new nodes */
/* oldlist = list of old nodes */
if(!(oldlist = curnode->Sub))
return;
dummylast.Prev = dummylast.Next = 0;
dummylast.Flags = FLAG_UNUSED;
list = &dummylast; /* the dummy entry is to make work easier and faster */
while((oldlist = InsertFront(list, oldlist)) && !(SetSignal(0L,0L) & SIGBREAKF_CTRL_C))
{
if(oldlist->Flags & (FLAG_DISKIMAGE|FLAG_INFOTEXT|FLAG_FILESYSTEM))
list = &dummylast; /* insert at end - in correct (unsorted) order */
else if(MyNodeComp(list, oldlist, mem) <= 0)
{
list = list->Next;
while(MyNodeComp(list, oldlist, mem) <= 0 && !(SetSignal(0L,0L) & SIGBREAKF_CTRL_C))
list = list->Next;
}
else /* insert before this */
{
while(list->Prev && (MyNodeComp(list->Prev, oldlist, mem) > 0) && !(SetSignal(0L,0L) & SIGBREAKF_CTRL_C))
list = list->Prev;
}
}
while(list->Prev)
list = list->Prev;
dummylast.Prev->Next = 0; /* remove last entry */
curnode->Sub = list; /* the start of list */
}
#endif /* MAKEREPLACEFIELD */